/**
 * 
 */
package biz.innovasoft.ndb;

import java.io.Serializable;
import java.util.List;

import biz.innovasoft.ndb.index.IndexException;
import biz.innovasoft.ndb.index.IndexManager;
import biz.innovasoft.ndb.index.Indexer;
import biz.innovasoft.ndb.index.Searcher;
import biz.innovasoft.ndb.query.Tuple;
import biz.innovasoft.ndb.util.IndexUtils;

/**
 * 
 * @author Diego Miranda
 *
 */
public class IndexHelper implements Serializable {

	private static final long serialVersionUID = 4802918532298085199L;
	
	private GenericRepository repository;
	
	public IndexHelper (GenericRepository repository) {
		this.repository = repository;
	}
	
	public void reindex() throws RepositoryException {
		
		/*
		 * Reinitialize all the indexes descriptions in the repository.
		 */
		for (Class<?> clazz : repository.getStoredClasses()) {
			IndexManager imanager = repository.getIndexManager(clazz);
			if (imanager == null) {
				imanager = new IndexManager(clazz);
					repository.getRepositoryIndexManager().addIndexManager(imanager);
			} else {
				imanager.initialize();
			}
		}
		
		/*
		 * Update all the indexes. 
		 */
		IndexManager[] managers = repository.getIndexManagers();
		for (IndexManager imanager : managers ) {
			Indexer indexer = null;
			try {
				indexer = new Indexer(imanager, false, true);
				List<Tuple> tuples = repository.getAll(imanager.getIndexClass());
				for (Tuple tuple : tuples) {
					indexer.indexObject(tuple.oid, tuple.value);
					indexObjectInRoot(tuple.oid, tuple.value);
				}
			} catch (IndexException e) {
				throw new RepositoryException(e);
			} finally {
				if (indexer != null)
					indexer.close();
			}
		}
	}
	
	public void reindex(Class<?> clazz) throws RepositoryException {
		IndexManager imanager = repository.getIndexManager(clazz);
		Indexer indexer = null;
		try {
			indexer = new Indexer(imanager, true, true);
			List<Tuple> tuples = repository.getAll(clazz);
			for (Tuple tuple : tuples) {
				indexer.indexObject(tuple.oid, tuple.value);
				indexObjectInRoot(tuple.oid, tuple.value);
			}
		} catch (IndexException e) {
			throw new RepositoryException(e);
		} finally {
			if (indexer != null)
				indexer.close();
		}
	}

	protected void reindex(IndexManager imanager) throws RepositoryException {
		Indexer indexer = null;
		try {
			indexer = new Indexer(imanager, true, true);
			Long[] ids = repository.getOIds();
			for (Long id : ids) {
				Object object = repository.getByOId(id);
				indexer.indexObject(id, object);
				if (!imanager.isRootIndex()) {
					indexObjectInRoot(id, object);
				}
			}
		} catch (IndexException e) {
			throw new RepositoryException(e);
		} finally {
			if (indexer != null)
				indexer.close();
		}
	}

	protected void reindexObject (Long oid, Object object) {
		deleteIndexObject (oid, object);
		indexObject (oid, object);
	}
	
	protected void deleteIndexObject (Long oid, Object object) {
		/* Delete reference from the object index */

		IndexManager imanager = repository.getIndexManager(object.getClass());
		Searcher searcher = new Searcher(imanager);
		searcher.deleteIndex(oid);
		
		
		/* Delete reference from the root index */
		imanager = repository.getRootIndexManager(object.getClass());
		searcher = new Searcher(imanager);
		searcher.deleteIndex(oid);
	}
	
	protected void indexObject(Long oid, Object object)
			throws RepositoryException {
		IndexManager imanager = repository.getIndexManager(object.getClass());
		Indexer indexer = null;
		try {
			indexer = new Indexer(imanager);
			indexer.indexObject(oid, object);
		} catch (IndexException e) {
			throw new RepositoryException(e);
		} finally {
			indexer.close();
		}
		indexObjectInRoot(oid, object);
	}
	
	protected void indexObjectInRoot(Long oid, Object object)
			throws RepositoryException {
		Class<?> root = IndexUtils.getRootClass(object.getClass());
		if (root.equals(object.getClass())) {
			return;
		}
		IndexManager imanager = repository.getRootIndexManager(root);
		Indexer indexer = null;
		try {
			indexer = new Indexer(imanager);
			indexer.indexObject(oid, object);
		} catch (IndexException e) {
			throw new RepositoryException(e);
		} finally {
			if (indexer != null) indexer.close();
		}
	}
	
}
